﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class ViewControllerNav : MonoBehaviour
{
    [SerializeField]
    private List<ViewController> m_Displays = new List<ViewController>();
    List<ViewController> m_Stack = new List<ViewController>();
    
    public ViewControllerLoadAnimation UIChangeAnimation;

    public Action<ViewController> OnDisplayClose;

    private void Awake()
    {
        
    }


    public T LoadDisplay<T>(Action<T> onInit,bool deletePreUI) where T : ViewController
    {
        T res = this.LoadDisplay<T>(typeof(T).Name,true, onInit, deletePreUI);
        return res;
    }
    public T LoadDisplay<T>() where T : ViewController
    {
        T res = this.LoadDisplay<T>(typeof(T).Name, true, null,true);
        return res;
    }
    public T LoadDisplay<T>(bool showAnim) where T : ViewController
    {
        T res = this.LoadDisplay<T>(typeof(T).Name, showAnim, null, true);
        return res;
    }

    //Dictionary<string, bool> m_DeletePreUI = new Dictionary<string, bool>();
    Dictionary<string, bool> m_PlayAnim = new Dictionary<string, bool>();

    //public float delayDeleteTime = 1f;

    /// <summary>
    /// 加载UI，先从m_Displays里找，找不到则创建
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <param name="displayId"></param>
    /// <returns></returns>
    public T LoadDisplay<T>(string displayId,bool showAnim,Action<T>onInit,bool DeletePreUI) where T : ViewController
    {
        if (string.IsNullOrEmpty(displayId))
            displayId = typeof(T).Name;

        Debug.Log("toload  displayId:" + displayId);


        //m_DeletePreUI[displayId] = DeletePreUI;
        m_PlayAnim[displayId] = showAnim;

        var prePeek = GetPeek();
        if (prePeek)
        {
            //Debug.Log("prePeek.name:" + prePeek.name);
        }

        T res = FindDisplay<T>(displayId);

        if (res == null)
        {
            res = CreateDisplay<T>(displayId, onInit);
        }
        else
        {
            if (m_Stack.Contains(res))
                MoveToTop(res);//若是前面已打开的界面则移到最顶层
            else
                m_Stack.Add(res);
        }

        res.deletePreView = DeletePreUI;

        try
        {
            if (onInit != null)
                onInit(res); //数据初始化执行最先
        }
        catch (Exception e)
        {
            GameDebug.LogError(e);
        }

/*        if (prePeek == res)
            prePeek = null;*/

        OnDCToActive(res, prePeek);

        return res;
    }

    bool animEnd = false;
    bool loadDCEnd = false;

    //public float dcInitAnimTime = 1f;
    /// <summary>
    /// 加载新界面，释放前界面
    /// </summary>
    /// <param name="dc"></param>
    /// <param name="prePeek"></param>
    /// <param name="create"></param>
    /// <returns></returns>
    void OnDCToActive(ViewController dc, ViewController prePeek)
    {
        if(dc.toDelete)
        {
            try
            {
                dc.OnViewDelete();
            } 
            catch (Exception e)
            {
                GameDebug.LogError(e);
            }

            dc.toDelete = false;
        }

        //首先播放淡入动画
        if (m_PlayAnim.ContainsKey(dc.viewId) && m_PlayAnim[dc.viewId] && UIChangeAnimation != null)
        {
            try
            {
                UIChangeAnimation.PlayShowAnimation(dc, () =>
                {
                    OnShowAnimEnd(dc, prePeek);
                });
            }
            catch (Exception e)
            {
                OnShowAnimEnd(dc, prePeek);
                GameDebug.LogError(e);
            }
        }
        else
        {
            DoActionDelay.DelayDoAction(0.010f, ()=> { OnShowAnimEnd(dc, prePeek); });
        }
    }

    
    //淡入动画播放完,接着播放加载动画，再下一帧再WillLoadDisplay
    void OnShowAnimEnd(ViewController dc, ViewController prePeek)
    {
        //Debug.Log("OnShowAnimEnd dc :" + dc.name + " prePeek: " + (prePeek == null ? "" : prePeek.name));
        loadDCEnd = false;

        bool notToPlayInLoadAnim = ((m_PlayAnim.ContainsKey(dc.viewId) && !m_PlayAnim[dc.viewId]) ||
                                 UIChangeAnimation == null);
            
        animEnd = notToPlayInLoadAnim;

        //播放加载动画
        if (!animEnd)
        {
            try
            { 
                UIChangeAnimation.PlayInLoadingAnimation(() =>
                {
                    OnPlayLoadingAnimEnd(dc, prePeek);
                });
            }
            catch (Exception e)
            {
                OnPlayLoadingAnimEnd(dc, prePeek);
                GameDebug.LogError(e);
            }
        }

        Action willLoadDisplay = delegate
        {
            if (dc.deletePreView && prePeek != null)
            {
#if DEBUG
                Debug.Log("prePeek.WillHideDisplay() prePeek :" + (prePeek != null ? prePeek.name : ""));
#endif
                try
                {
                    prePeek.WillHideView();
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }

                OnDisplayClose?.Invoke(prePeek);
                prePeek.toDelete = true;
            }

            try
            {
                Debug.Log("pwillLoadDisplay :" + (dc != null ? dc.name : ""));
                //加载数据
                dc.WillLoadView(
                    (d) => { OnDCWillLoadDisplayEnd(d, prePeek); });
            }
            catch (Exception e)
            {
                Debug.LogError(e);

                OnDCWillLoadDisplayEnd(dc, prePeek);
            }
        };

        //yield return 0;

        //协程改为Invoke
        //Invoke("DoWillLoad",0.016f);
        if (notToPlayInLoadAnim)
        {
            willLoadDisplay();
        }
        else
        {
            DoActionDelay.DelayDoAction(0.010f,willLoadDisplay);
        }
    }
    
    private DoActionDelay _mDoActionDelay;
    public DoActionDelay DoActionDelay
    {
        get
        {
            if (_mDoActionDelay == null)
            {
                _mDoActionDelay = gameObject.AddComponent<DoActionDelay>();
            }
            return _mDoActionDelay;
        }
    }

    void OnDCWillLoadDisplayEnd(ViewController dc, ViewController prePeek)
    {
       // Debug.LogError("OnDCWillLoadDisplayEnd !!  dc:" + dc.name+ "  animEnd:"+ animEnd);
        //数据加载完，若加载动画播放完则播放淡出动画
        loadDCEnd = true;
        if (animEnd)
        {
            DidLoadDisplay(dc, prePeek);
        }
    }

    void OnPlayLoadingAnimEnd(ViewController dc, ViewController prePeek)
    {
       // Debug.LogError("OnPlayLoadingAnimEnd !!  dc:" + dc.name);
        animEnd = true;

        //加载动画播放完，若数据加载完则播放淡出动画
        if (loadDCEnd)
        {
            DidLoadDisplay(dc, prePeek);
        }
    }


    void OnDidLoadDisplayEnd(ViewController dc, ViewController prePeek)
    {
        if (m_PlayAnim.ContainsKey(dc.viewId) && m_PlayAnim[dc.viewId] && UIChangeAnimation != null)
        {
            try
            { 
                UIChangeAnimation.PlayHideAnimation(
                () =>
                {
                    OnLoadDCHideAnimEnd(dc);
                });
                
            } 
            catch (Exception e)
            {
                Debug.LogError(e);
                OnLoadDCHideAnimEnd(dc);
            }
        }
        else
        {
            OnLoadDCHideAnimEnd(dc);
        }

    }

    /// <summary>
    /// 加载新界面的淡出动画播放完
    /// </summary>
    /// <param name="toShowView"></param>
    /// <param name="toDeleteDisplay"></param>
    void OnLoadDCHideAnimEnd(ViewController toShowView)//, DisplayController toDeleteDisplay)
    {
        if (toShowView != null)
            toShowView.OnLoadedViewEnd();
    }

    /// <summary>
    /// 关闭界面，唤起前界面
    /// </summary>
    /// <param name="dc"></param>
    /// <param name="nextPeek"></param>
    /// <returns></returns>
    void OnDCToDisActive(ViewController dc,ViewController nextPeek)
    {
        Debug.Log("GoBackToPreDC OnDCToDisActive:" + dc.name);
        try
        {
            dc.OnDidHideView(() =>
            {
                if (m_PlayAnim.ContainsKey(dc.viewId) && m_PlayAnim[dc.viewId] && UIChangeAnimation != null)
                {
                   // Debug.LogError("OnDCToDisActive  PlayHideAnim:" + dc.name);
                   try
                   {
                       UIChangeAnimation.PlayHideAnimation(
                           () => { OnGoBackHideAnimEnd(dc); });
                   }
                   catch (Exception e)
                   {
                       OnGoBackHideAnimEnd(dc);
                       GameDebug.LogError(e);
                   }
                }
                else
                {
                    OnGoBackHideAnimEnd(dc);
                }

                //打开前界面
                if (dc .deletePreView && nextPeek != null)
                {
                    JustActiveDC(nextPeek);
                }
            }
                );
        }
        catch (Exception e)
        {
            GameDebug.LogError(e);
            
            OnGoBackHideAnimEnd(dc);
            //打开前界面
            if (dc .deletePreView && nextPeek != null)
            {
                JustActiveDC(nextPeek);
            }
        }
    }
    void JustActiveDC(ViewController dc)
    {
        try
        {
            dc.WillLoadView((d)=> 
            {
                DidLoadDisplay(d, null);
            });
        }
        catch (Exception e)
        {
            Debug.LogError(e);

            DidLoadDisplay(dc,null);
        }
    }

    /// <summary>
    /// WillLoadDisplay 执行完，则执行OnDidLoadDisplay
    /// </summary>
    /// <param name="dc"></param>
    void DidLoadDisplay(ViewController dc, ViewController prePeek)
    {
        var didload = new Action(()=>
        {
            try
            {
                dc.OnDidLoadView(() => { OnDidLoadDisplayEnd(dc, prePeek); });
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                OnDidLoadDisplayEnd(dc, prePeek);
            }
        });
        
        try
        {
            if (prePeek)
            {
                prePeek.OnDidHideView(didload);
            }
            else
            {
                didload.Invoke();
            }
        } 
        catch (Exception e)
        {
            Debug.LogError(e);
            
            didload.Invoke();
        }

    }

    ///// <summary>
    ///// 移到最顶层
    ///// </summary>
    ///// <param name="dc"></param>
    void MoveToTop(ViewController dc)
    {
        var exist = m_Stack.Find(e => e == dc);
        if (exist != null)
        {
            m_Stack.Remove(exist);
            m_Stack.Add(exist);
        }
    }

    ///// <summary>
    ///// 获取最顶层UI
    ///// </summary>
    ///// <returns></returns>
    public ViewController GetPeek()
    {
        if (m_Stack.Count == 0)
            return null;
        else
            return m_Stack[m_Stack.Count - 1];
    }
    /// <summary>
    /// 出栈
    /// </summary>
    /// <returns></returns>
    ViewController Pop()
    {
        var peek = GetPeek();
        if (peek != null)
            m_Stack.Remove(peek);

        return peek;
    }
    /// <summary>
    /// 创建UI
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <param name="displayId"></param>
    /// <returns></returns>
    private T CreateDisplay<T>(string displayId, Action<T> onInit) where T : ViewController
    {
        var go = new UnityEngine.GameObject(typeof(T).ToString());
        T res = go.AddComponent<T>();
        res.viewId = displayId;
        res.transform.SetParent(transform);
        m_Displays.Add(res);
        m_Stack.Add(res);
        
        return res;
    }


    /// <summary>
    /// 从缓存中找
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="displayId"></param>
    /// <returns></returns>
    public T FindDisplay<T>(string displayId) where T : ViewController
    {
        T res = m_Displays.Find(e => e.GetType().Equals(typeof(T))&& e.viewId == displayId) as T;
        return res;
    }
    public T FindDisplay<T>() where T : ViewController
    {
        T res = m_Displays.Find(e => e.GetType().Equals(typeof(T))) as T;
        return res;
    }


	/// <summary>
    /// 从某个UI返回
    /// </summary>
    /// <param name="controller"></param>
  //  public void GoBackDisplay()
  //  {
		//if (m_Stack.Count > 1)
		//{
		//	DisplayController controller = Pop();//移出

  //      }
  //  }

    public void Remove(ViewController dc)
    {
        if (m_Stack.Contains(dc))
        {
            m_Stack.Remove(dc);
        }
    }

    public void GoBackToPreDC()
    {
        ViewController controller = Pop();//移出
        try
        {
            controller.WillHideView();
            OnDisplayClose?.Invoke(controller);

            controller.toDelete = true;
        }
        catch { }

        var nextPeek = GetPeek();

        OnDCToDisActive(controller, nextPeek);
    }

    /// <summary>
    /// 关闭界面的淡出动画播放完
    /// </summary>
    /// <param name="toDeleteDC"></param>
    /// <param name="delete"></param>
    void OnGoBackHideAnimEnd(ViewController toDeleteDC)
    {
        if (toDeleteDC)
            toDeleteDC.OnViewDelete();

    }
    
    public void ReleaseAll()
    {
        foreach(var display in m_Displays)
        {
            if(display)
            {
                try
                {
                    display.WillHideView();
                    OnDisplayClose?.Invoke(display);

                }
                catch { }

                try
                {
                    display.OnDidHideView(null);
                }
                catch { }
                
                try
                {
                    display.OnViewDelete();
                } 
                catch { }
            }
        }
        m_Stack.Clear();

        if (this.UIChangeAnimation)
        {
            Destroy(UIChangeAnimation.gameObject);
        }
    }

    public int GetIndex(ViewController dc)
    {
        if(m_Stack.Contains(dc))
            return m_Stack.IndexOf(dc);
        return 0;
    }

    private void OnDestroy()
    {
        if(this.UIChangeAnimation)
            Destroy(UIChangeAnimation.gameObject);
    }
}
